import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;

import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WordUtils {

    /**
     * 在指定段落后插入一个普通段落，支持：
     * - 下划线字段（_张三_）
     * - 自定义段落样式
     * - 顶格输出
     * - 宋体四号（14pt）
     *
     * @param doc           XWPFDocument 文档对象
     * @param afterIndex    插入位置（在第 afterIndex 段落后）
     * @param text          段落文本，支持下划线字段（_张三_）
     * @param indentation   首行缩进几个字符
     */
    public static void insertStyledParagraph(XWPFDocument doc, int afterIndex, String text,int indentation) {
        try {
            List<XWPFParagraph> allParagraphs = doc.getParagraphs();
            if (afterIndex < 0 || afterIndex >= allParagraphs.size()) {
                throw new IllegalArgumentException("afterIndex 越界");
            }

            XWPFParagraph refPara = allParagraphs.get(afterIndex);
            XWPFParagraph newPara = doc.insertNewParagraph(refPara.getCTP().newCursor());

            // -----------------------------
            // 顶格输出（取消缩进）
            // -----------------------------
            newPara.setIndentationLeft(0);//设置段落的左边距。
            newPara.setIndentationHanging(0);//设置悬挂缩进
            newPara.setIndentationFirstLine(indentation*20);//设置段落首行缩进
            newPara.setSpacingBeforeLines(0);//设置段前间距
            newPara.setSpacingAfterLines(0);//设置段后间距
            newPara.setSpacingBetween(1.0);//设置行间距


            // -----------------------------
            // 解析文本，生成下划线字段
            // -----------------------------
            Pattern pattern = Pattern.compile("_(.+?)_");
            Matcher matcher = pattern.matcher(text);
            int lastEnd = 0;
            while (matcher.find()) {
                // 普通文字
                String beforeText = text.substring(lastEnd, matcher.start());
                if (!beforeText.isEmpty()) {
                    XWPFRun run = newPara.createRun();
                    run.setText(beforeText);
                    run.setFontFamily("宋体");
                    run.setFontSize(14);
                    run.getCTR().addNewRPr().addNewRFonts().setEastAsia("宋体");
                }

                // 下划线文字
                String underlinedText = matcher.group(1);
                XWPFRun underlineRun = newPara.createRun();
                underlineRun.setText(underlinedText);
                underlineRun.setUnderline(UnderlinePatterns.SINGLE);
                underlineRun.setFontFamily("宋体");
                underlineRun.setFontSize(14);
                underlineRun.getCTR().addNewRPr().addNewRFonts().setEastAsia("宋体");

                lastEnd = matcher.end();
            }

            // 最后普通文字
            if (lastEnd < text.length()) {
                XWPFRun lastRun = newPara.createRun();
                lastRun.setText(text.substring(lastEnd));
                lastRun.setFontFamily("宋体");
                lastRun.setFontSize(14);
                lastRun.getCTR().addNewRPr().addNewRFonts().setEastAsia("宋体");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 在文档中查找关键字，并用图片替换。
     * 支持文档顶层段落和表格中的段落。
     *
     * @param doc       XWPFDocument 文档对象
     * @param keyword   要替换的关键字
     * @param imagePath 图片路径（png/jpg）
     * @param width     图片宽度（像素）
     * @param height    图片高度（像素）
     * @throws Exception
     */
    public static void replaceKeywordWithImage(XWPFDocument doc, String keyword,
                                               String imagePath, int width, int height) throws Exception {
        // 处理顶层段落
        for (XWPFParagraph para : doc.getParagraphs()) {
            replaceInParagraph(para, keyword, imagePath, width, height);
        }

        // 处理文档表格
        for (XWPFTable table : doc.getTables()) {
            replaceInTable(table, keyword, imagePath, width, height);
        }
    }

    // -------------------- 私有方法 --------------------

    private static void replaceInTable(XWPFTable table, String keyword,
                                       String imagePath, int width, int height) throws Exception {
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                // 替换单元格内段落
                for (XWPFParagraph para : cell.getParagraphs()) {
                    replaceInParagraph(para, keyword, imagePath, width, height);
                }
                // 如果单元格里还有嵌套表格，递归处理
                for (XWPFTable innerTable : cell.getTables()) {
                    replaceInTable(innerTable, keyword, imagePath, width, height);
                }
            }
        }
    }

    private static void replaceInParagraph(XWPFParagraph para, String keyword,
                                           String imagePath, int width, int height) throws Exception {
        List<XWPFRun> runs = para.getRuns();
        for (int i = 0; i < runs.size(); i++) {
            XWPFRun run = runs.get(i);
            String runText = run.getText(0);
            if (runText != null && runText.contains(keyword)) {

                // 拆分 run，保留关键字前后的文字
                String before = runText.substring(0, runText.indexOf(keyword));
                String after = runText.substring(runText.indexOf(keyword) + keyword.length());

                run.setText(before, 0); // 替换原 run 为关键字前的文字

                // 插入图片
                try (FileInputStream is = new FileInputStream(imagePath)) {
                    run.addPicture(is, getPictureType(imagePath), imagePath,
                            Units.toEMU(width), Units.toEMU(height));
                }

                // 插入关键字后的文字
                if (!after.isEmpty()) {
                    XWPFRun afterRun = para.insertNewRun(i + 1);
                    afterRun.setText(after);
                    afterRun.setFontFamily("宋体");
                    afterRun.setFontSize(14);
                }

                return; // 替换一次就退出
            }
        }
    }

    // 根据文件后缀返回图片类型
    private static int getPictureType(String imagePath) {
        if (imagePath.endsWith(".png") || imagePath.endsWith(".PNG")) {
            return XWPFDocument.PICTURE_TYPE_PNG;
        } else if (imagePath.endsWith(".jpg") || imagePath.endsWith(".jpeg") || imagePath.endsWith(".JPG")) {
            return XWPFDocument.PICTURE_TYPE_JPEG;
        } else if (imagePath.endsWith(".bmp") || imagePath.endsWith(".BMP")) {
            return XWPFDocument.PICTURE_TYPE_BMP;
        } else if (imagePath.endsWith(".gif") || imagePath.endsWith(".GIF")) {
            return XWPFDocument.PICTURE_TYPE_GIF;
        } else {
            throw new IllegalArgumentException("不支持的图片类型: " + imagePath);
        }
    }






    /**
     * 批量替换 Word 表格关键字
     *
     * @param doc  XWPFDocument 文档对象
     * @param data Map<占位符, 替换值>
     */
    public static void replaceTableKeywords(XWPFDocument doc, Map<String, String> data) {

        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    // 替换单元格段落
                    for (XWPFParagraph para : cell.getParagraphs()) {
                        replaceInParagraph(para, data);
                    }

                    // 如果单元格里还有嵌套表格，递归处理
                    for (XWPFTable innerTable : cell.getTables()) {
                        replaceTableKeywordsInTable(innerTable, data);
                    }
                }
            }
        }
    }

    private static void replaceTableKeywordsInTable(XWPFTable table, Map<String, String> data) {
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                for (XWPFParagraph para : cell.getParagraphs()) {
                    replaceInParagraph(para, data);
                }
                for (XWPFTable innerTable : cell.getTables()) {
                    replaceTableKeywordsInTable(innerTable, data);
                }
            }
        }
    }

    private static void replaceInParagraph(XWPFParagraph para, Map<String, String> data) {
        List<XWPFRun> runs = para.getRuns();
        for (XWPFRun run : runs) {
            String text = run.getText(0);
            if (text != null) {
                for (Map.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (text.contains(key)) {
                        text = text.replace(key, value);
                        run.setText(text, 0);
                    }
                }
            }
        }
    }
}
